package mobileMoney;

import sim.engine.SimState;
import sim.field.network.Edge;
import sim.util.Bag;
import sim.util.Double2D;
import sim.util.MutableDouble2D;

public class ClientSimA extends Client {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public void step(SimState state) {
		Clients clients = (Clients) state;
		Bag out = clients.contacts.getEdgesOut(this);
		// probability to make a transaction
		if (this.active) {
			// activates or deactivate a client and upgrade status
			evaluateStatus(clients.random.nextDouble());

			int typeTransaction = this.evaluateTransaction(clients.random
					.nextDouble());

			// select one transaction
			int numOp = clients.random.nextInt(100);
			TransactionType operation = clients.getTypes().get(numOp);
			double amount, limit;
			if (typeTransaction == 1) { // deposit
				limit = this.profile.maxBalance - this.balance;
				amount = this.evaluateAmount(operation, clients, limit);
				if (this.deposit(amount)) {
					clients.getTrans().add(
							new Transaction(clients.schedule.getSteps(), this,
									(short) typeTransaction, amount,
									" Deposit " + operation.toString()));
				}
			} else if (typeTransaction == 2) { // withdraw
				limit = this.balance;
				amount = this.evaluateAmount(operation, clients, limit);
				if (this.withdraw(amount)) {
					clients.getTrans().add(
							new Transaction(clients.schedule.getSteps(), this,
									(short) typeTransaction, -amount,
									"Withdraw" + operation.toString()));
				}
			} else if (typeTransaction == 3) { // transfer
				limit = this.balance;
				int len = out.size();
				// loop the contacts
				int contact = 0;

				if (len > 0) {
					contact = clients.random.nextInt(len);
				}
				Edge e = (Edge) (out.get(contact));
				Client clientB = (Client) (e.getOtherNode(this));

				amount = this.evaluateAmount(operation, clients, limit);

				this.numTransfers++;
				// only when is possible to deposit
				if (clientB.checkDeposit(amount)) {
					if (this.withdraw(amount)) {
						clients.getTrans().add(
								new Transaction(clients.schedule.getSteps(),
										this, clientB, (short) typeTransaction,
										-amount, "Transfer to B "
												+ operation.toString()));
						clientB.deposit(amount);
						clients.getTrans().add(
								new Transaction(clients.schedule.getSteps(),
										clientB, this, (short) typeTransaction,
										amount, " deposited from B "
												+ operation.toString()));
					}
				}
			}
			Double2D me = clients.land.getObjectLocation(this);
			MutableDouble2D newLoc = new MutableDouble2D();
			// move the agents
			double lx = clients.randomMultiplier
					* (clients.random.nextDouble() * 1.0 - 0.5);
			if (lx > 100)
				lx = 99;
			double ly = clients.randomMultiplier
					* (clients.random.nextDouble() * 1.0 - 0.5);
			if (ly > 100)
				ly = 99;

			newLoc.addIn(new Double2D(lx, ly));
			newLoc.addIn(me);
			clients.land.setObjectLocation(this, new Double2D(newLoc));
		}
	}
}
